package com.byf.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.byf.common.core.utils.StringUtils;
import com.byf.search.common.domain.SkuEsModel;
import com.byf.search.constant.SearchConstants;
import com.byf.search.service.ProductService;
import com.byf.search.vo.SearchParam;
import com.byf.search.vo.SearchResult;
import lombok.extern.log4j.Log4j2;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.nested.NestedAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.nested.ParsedNested;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.xcontent.XContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;



@Service
@Log4j2
public class ProductServiceImpl implements ProductService {


    @Autowired
    private RestHighLevelClient client;


    @Override
    public boolean productStatsUp(List<SkuEsModel> skuEsModelList) {
        BulkRequest bulkRequest = new BulkRequest();
        skuEsModelList.stream().forEach(skuEsModel -> {


            IndexRequest indexRequest = new IndexRequest();
            indexRequest.index("product");
            indexRequest.id(skuEsModel.getSkuId().toString());
            indexRequest.source(JSON.toJSONString(skuEsModel), XContentType.JSON);
            bulkRequest.add(indexRequest);


        });
        BulkResponse bulk = null;
        try {
            bulk = client.bulk(bulkRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        boolean b = bulk.hasFailures();
        return b;

    }

    /**
     * 商品es搜索
     * @param searchParam
     * @return
     */
    @Override
    public SearchResult search(SearchParam searchParam) throws IOException {
        //构建searchRequest
        SearchRequest searchRequest = buildSearchRequest(searchParam);

        //执行search
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);

        //解析response
        SearchResult searchResult = analyerResponse(searchResponse,searchParam);
        return searchResult;
    }

    /**
     * 解析response
     * @param searchResponse
     * @param searchParam
     * @return
     */
    private SearchResult analyerResponse(SearchResponse searchResponse, SearchParam searchParam) {
        SearchResult searchResult = new SearchResult();

        //hits
        SearchHits hits = searchResponse.getHits();

        //查询到的所有商品信息
        List<SkuEsModel> skuEsModelList = new ArrayList<>();
        for (SearchHit hit : hits.getHits()) {
            String skuEsModelString = hit.getSourceAsString();
            SkuEsModel skuEsModel = JSON.parseObject(skuEsModelString, SkuEsModel.class);

            if (StringUtils.isNotBlank(searchParam.getKeyword())) {
                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                HighlightField skuTitleHighlightField = highlightFields.get("skuTitle");

                if (skuTitleHighlightField != null) {
                    Text[] fragments = skuTitleHighlightField.getFragments();
                    if (fragments != null && fragments.length > 0) {
                        // 使用高亮字段替换原始字段值
                        skuEsModel.setSkuTitle(fragments[0].toString());
                    } else {
                        // 如果没有高亮片段，可以使用原始的 skuTitle 字段值
                        // 这取决于您的业务逻辑需求
                        log.warn("No highlight fragments found for skuTitle in hit: {}", hit.getId());
                    }
                } else {
                    // 如果没有找到高亮字段，可以使用原始的 skuTitle 字段值
                    // 或者根据需要处理缺失的高亮字段
                    log.warn("No highlight field found for skuTitle in hit: {}", hit.getId());
                }
            }

            skuEsModelList.add(skuEsModel);
        }

        searchResult.setProducts(skuEsModelList);
        //当前页码
        searchResult.setPageNum(searchParam.getPageNum());
        //总记录数
        searchResult.setTotal(hits.getTotalHits().value);
        //总页码
        searchResult.setTotalPages(Long.valueOf(searchResult.getTotal()%20==0?searchResult.getTotal()/20:(searchResult.getTotal()/20+1)).intValue());

        /**
         * 以下是agg聚合结果           解析
         */
        Aggregations aggregations = searchResponse.getAggregations();
        //当前查询到的结果，所有涉及到的品牌
        ParsedLongTerms brandIdAgg = aggregations.get("brandIdAgg");
        List<? extends Terms.Bucket> buckets = brandIdAgg.getBuckets();
        ArrayList<SearchResult.BrandVo> brandVos = new ArrayList<>();
        for (Terms.Bucket bucket : buckets) {
            SearchResult.BrandVo brandVo = new SearchResult.BrandVo();
            brandVo.setBrandId(Long.valueOf(bucket.getKeyAsString()));

            Terms brandNameAgg = bucket.getAggregations().get("brandNameAgg");
            String brandName = brandNameAgg.getBuckets().get(0).getKeyAsString();
            brandVo.setBrandName(brandName);
            brandVos.add(brandVo);
        }
        searchResult.setBrands(brandVos);
        //当前查询到的结果，所有涉及到的分类
        ArrayList<SearchResult.CatalogVo> catalogs = new ArrayList<>();
        ParsedLongTerms catalogIdAgg = aggregations.get("catalogIdAgg");

        List<? extends Terms.Bucket> catalogIdAggBuckets = catalogIdAgg.getBuckets();

        for (Terms.Bucket catalogBucket : catalogIdAggBuckets) {
            SearchResult.CatalogVo catalogVo = new SearchResult.CatalogVo();
            String catalogId = catalogBucket.getKeyAsString();
            catalogVo.setCatalogId(Long.valueOf(catalogId));
            Terms catalogNameAgg = catalogBucket.getAggregations().get("catalogNameAgg");
            String catalogName = catalogNameAgg.getBuckets().get(0).getKeyAsString();
            catalogVo.setCatalogName(catalogName);
            catalogs.add(catalogVo);
        }
        searchResult.setCatalogs(catalogs);
        //当前查询的结果，所有涉及到的所有属性
        List<SearchResult.AttrVo> attrs = new ArrayList<>();
        ParsedNested attrsAgg = aggregations.get("attrAgg");

        if (attrsAgg != null) {
            Aggregations nestedAggs = attrsAgg.getAggregations();
            if (nestedAggs != null) {
                Terms attrIdAgg = nestedAggs.get("attrIdAgg");
                if (attrIdAgg != null) {
                    for (Terms.Bucket bucket : attrIdAgg.getBuckets()) {
                        SearchResult.AttrVo attrVo = new SearchResult.AttrVo();

                        // attrId
                        String attrId = bucket.getKeyAsString();
                        try {
                            attrVo.setAttrId(Long.valueOf(attrId));
                        } catch (NumberFormatException e) {
                            log.warn("Invalid attrId format: {}", attrId, e);
                            continue;
                        }

                        Aggregations attrIdBucketAggregations = bucket.getAggregations();
                        if (attrIdBucketAggregations != null) {
                            // attrName
                            Terms attrNameAgg = attrIdBucketAggregations.get("attrNameAgg");
                            if (attrNameAgg != null && !attrNameAgg.getBuckets().isEmpty()) {
                                String attrName = attrNameAgg.getBuckets().get(0).getKeyAsString();
                                attrVo.setAttrName(attrName);
                            } else {
                                log.warn("No attrNameAgg buckets found for attrId: {}", attrId);
                            }

                            // attrValues []
                            Terms attrValueAgg = attrIdBucketAggregations.get("attrValueAgg");
                            if (attrValueAgg != null) {
                                List<String> values = new ArrayList<>();
                                for (Terms.Bucket attrValueAggBucket : attrValueAgg.getBuckets()) {
                                    values.add(attrValueAggBucket.getKeyAsString());
                                }
                                attrVo.setAttrValue(values);
                            } else {
                                log.warn("No attrValueAgg found for attrId: {}", attrId);
                            }
                        } else {
                            log.warn("No aggregations found for attrId: {}", attrId);
                        }

                        attrs.add(attrVo);
                    }
                } else {
                    log.warn("No attrIdAgg found in nested aggregations.");
                }
            } else {
                log.warn("No aggregations found within 'attrsAgg'");
            }
        } else {
            log.warn("No nested aggregation found for 'attrsAgg'");
        }

        searchResult.setAttrs(attrs);

        return searchResult;
    }

    /**
     * 构建searchRequest
     * @param searchParam
     * @return
     */
    private SearchRequest buildSearchRequest(SearchParam searchParam) {
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        //keyword
        if (StringUtils.isNotEmpty(searchParam.getKeyword())){
            boolQueryBuilder.must(QueryBuilders.matchQuery("skuTitle",searchParam.getKeyword()));
        }

        //catalog
        if (searchParam.getCatalog3Id()!=null){
            boolQueryBuilder.filter(QueryBuilders.termQuery("catalogId",searchParam.getCatalog3Id()));
        }

        //brandId
        if (searchParam.getBrandId()!=null && searchParam.getBrandId().size()>0){
            boolQueryBuilder.filter(QueryBuilders.termsQuery("brandId",searchParam.getBrandId()));
        }

        //skuPrice
        if (StringUtils.isNotBlank(searchParam.getSkuPrice())){
            RangeQueryBuilder skuPrice = QueryBuilders.rangeQuery("skuPrice");

            String[] prices = searchParam.getSkuPrice().split("_");
            if (prices.length==2){
                skuPrice.lte(prices[1]);
                skuPrice.gte(prices[0]);
            }else if (searchParam.getSkuPrice().startsWith("_")){
                skuPrice.lte(prices[1]);
            }else if (searchParam.getSkuPrice().endsWith("_")){
                skuPrice.gte(prices[0]);
            }
            boolQueryBuilder.filter(skuPrice);
        }

        //nested attrs 1_3:3&2_4:8
        if (!CollectionUtils.isEmpty(searchParam.getAttrs())){
            for (String attrStr : searchParam.getAttrs()) {
                String[] splitAttrIdAttrValues = attrStr.split("_");
                Long attrId = Long.valueOf(splitAttrIdAttrValues[0]);
                String[] attrValues = splitAttrIdAttrValues[1].split(":");

                BoolQueryBuilder attrIdValuesBoolQueryBuilder = QueryBuilders.boolQuery();
                attrIdValuesBoolQueryBuilder.must(QueryBuilders.termQuery("attrs.attrId",attrId));
                attrIdValuesBoolQueryBuilder.must(QueryBuilders.termsQuery("attrs.attrValue",attrValues));

                boolQueryBuilder.filter(QueryBuilders.nestedQuery("attrs",attrIdValuesBoolQueryBuilder, ScoreMode.None));
            }
        }
        sourceBuilder.query(boolQueryBuilder);

        //sort
        if (StringUtils.isNotBlank(searchParam.getSort())){
            String[] strings = searchParam.getSort().split("_");

            sourceBuilder.sort(strings[0],"asc".equalsIgnoreCase(strings[1])?SortOrder.ASC:SortOrder.DESC);
        }

        //分页
        sourceBuilder.from(searchParam.getPageNum());
        sourceBuilder.size(SearchConstants.PAGESIZE);

        //高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("skuTitle");
        highlightBuilder.preTags("<span style='color:skyblue;font-size:18px'>");
        highlightBuilder.postTags("</span>");

        //aggs
        TermsAggregationBuilder brandIdAgg = AggregationBuilders.terms("brandIdAgg").field("brandId");
        TermsAggregationBuilder brandNameAgg = AggregationBuilders.terms("brandNameAgg").field("brandName");
        TermsAggregationBuilder brandImgAgg = AggregationBuilders.terms("brandImgAgg").field("brandImg");
        brandIdAgg.subAggregation(brandNameAgg);
        brandIdAgg.subAggregation(brandImgAgg);

        TermsAggregationBuilder catalogIdAgg = AggregationBuilders.terms("catalogIdAgg").field("catalogId");
        TermsAggregationBuilder catalogNameAgg = AggregationBuilders.terms("catalogNameAgg").field("catalogName");
        catalogIdAgg.subAggregation(catalogNameAgg);

        NestedAggregationBuilder nested = AggregationBuilders.nested("attrAgg", "attrs");
        TermsAggregationBuilder attrIdAgg = AggregationBuilders.terms("attrIdAgg").field("attrs.attrId");
        TermsAggregationBuilder attrNameAgg = AggregationBuilders.terms("attrNameAgg").field("attrs.attrName");
        TermsAggregationBuilder attrValueAgg = AggregationBuilders.terms("attrValueAgg").field("attrs.attrValue");

        nested.subAggregation(attrIdAgg);
        attrIdAgg.subAggregation(attrNameAgg);
        attrIdAgg.subAggregation(attrValueAgg);

        sourceBuilder.aggregation(brandIdAgg);
        sourceBuilder.aggregation(catalogIdAgg);
        sourceBuilder.aggregation(nested);

        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices("product");
        searchRequest.source(sourceBuilder);
        return searchRequest;
    }


}
